/**
 * Copyright (c) 2018, 西安星沙网络科技-版权所有
 *
 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.waleychain.exchange.service.impl.account;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.mail.BodyPart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;
import com.jsuportframework.util.JSUtils;

import cn.waleychain.exchange.core.SysParaKey;
import cn.waleychain.exchange.core.constant.DDIC;
import cn.waleychain.exchange.core.email.EmailConfig;
import cn.waleychain.exchange.core.email.EmailUtils;
import cn.waleychain.exchange.core.entity.PageInfo;
import cn.waleychain.exchange.core.result.RetResultCode;
import cn.waleychain.exchange.core.utils.AliyunUtils;
import cn.waleychain.exchange.core.utils.BigDecimalUtils;
import cn.waleychain.exchange.core.utils.PageHelper;
import cn.waleychain.exchange.core.utils.RandomUtils;
import cn.waleychain.exchange.core.utils.SequenceUtils;
import cn.waleychain.exchange.core.utils.StringUtils;
import cn.waleychain.exchange.core.vaildate.VaildateHelper;
import cn.waleychain.exchange.dao.ActivationCodeMapper;
import cn.waleychain.exchange.dao.UserAccountMapper;
import cn.waleychain.exchange.dao.UserBankMapper;
import cn.waleychain.exchange.dao.UserInfoMapper;
import cn.waleychain.exchange.feign.CoinServiceFeign;
import cn.waleychain.exchange.feign.CoinWalletServiceFeign;
import cn.waleychain.exchange.feign.ConfigServiceFeign;
import cn.waleychain.exchange.model.ActivationCode;
import cn.waleychain.exchange.model.CoinInfo;
import cn.waleychain.exchange.model.CoinWallet;
import cn.waleychain.exchange.model.UserAccount;
import cn.waleychain.exchange.model.UserBank;
import cn.waleychain.exchange.model.UserInfo;
import cn.waleychain.exchange.service.account.UserService;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserInfoMapper userMapper;
	
	@Autowired
	private UserAccountMapper userAccountMapper;
	
	@Autowired
	private UserBankMapper userBankMaper;
	
	@Autowired
	private CoinServiceFeign coinFeign;
	
	@Autowired
	private CoinWalletServiceFeign coinWalletFeign;
	
	@Autowired
	private ConfigServiceFeign configFeign;
	
	@Autowired
	private ActivationCodeMapper activationCodeMapper;
	
	@Override
	public long fetchAdminUserId() {
		
		String s = null;
		try {
			s = configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_PLATFORM_USER_ID);
		} catch (Exception e) {
		}
		
		if (StringUtils.isNotBlank(s)) {
			return Long.parseLong(s);
		}
		
		return 0L;
	}
	
	@Override
	@Transactional
	public UserInfo addUserInfo(UserInfo user) throws Exception {

		boolean bool = userMapper.fetchCountByMobile(user.getMobile()) > 0;
		VaildateHelper.vaildateBooleanResult(bool, RetResultCode.E20007);
		
		// 验证邀请码
		if (StringUtils.isNotBlank(user.getInvitionCode())) {
			// 邀请人
			UserInfo invitionUser = userMapper.fetchUserByInvitionCode(user.getInvitionCode());
			VaildateHelper.vaildateBooleanResult(invitionUser == null, RetResultCode.E20010);
			
			user.setInviterId(invitionUser.getUserId());
			// 生成自己的邀请码
			String invitionCode = RandomUtils.genRandomUpperAlphaAndDec(8);
			UserInfo hasExist = userMapper.fetchUserByInvitionCode(invitionCode);
			while (hasExist != null) { // 保证邀请码唯一
				invitionCode = RandomUtils.genRandomUpperAlphaAndDec(8);
			}
			user.setInvitionCode(invitionCode);
		}
		
		// 创建资金账户
		UserAccount account = new UserAccount();
		account.setAccountId(SequenceUtils.generateDefaultSerialNum());
		account.setUserId(user.getUserId());
		account.setBalance(BigDecimalUtils.genInitValue());
		account.setFreeze(BigDecimalUtils.genInitValue());
		account.setStatus(DDIC.UserAccountStatus.ENABLED.id);
		account.setCreateTime(new Date());
		account.setModifiedTime(new Date());
		
		boolean bool1 = userMapper.insertSelective(user) > 0;
		boolean bool2 = userAccountMapper.insertSelective(account) > 0;
		
		boolean result = bool1 && bool2;
		if (result) {
			// 同步账号
			this.syncAccount(user.getUserId());
			
			return user;
		}
		
		return null;
	}
	
	@Override
	public UserInfo emailRgstry(String email, String password, String invitionCode) throws Exception {

		boolean b = userMapper.fetchCountByEmail(email) > 0;
		VaildateHelper.vaildateBooleanResult(b, RetResultCode.E20007);
		
		UserInfo user = new UserInfo();
		user.setUserId(SequenceUtils.generateDefaultSerialNum());
		user.setUserName(email);
		user.setPassword(password);
		user.setEmail(email);
		user.setIsSetPayPassword(DDIC.Boolean.BOOL_FALSE_0.id);
		user.setStatus(DDIC.UserAccountStatus.DISABLED.id);
		user.setAuthLevel(DDIC.UserAuthLevel.AUTH_LEVEL_1.id);
		user.setInvitionCode(invitionCode);
		user.setIsDeductible(DDIC.Boolean.BOOL_FALSE_0.id);
		user.setCreateTime(new Date());
		user.setModifiedTime(new Date());
		
		// 验证邀请码
		if (StringUtils.isNotBlank(invitionCode)) {
			// 邀请人
			UserInfo invitionUser = userMapper.fetchUserByInvitionCode(invitionCode);
			VaildateHelper.vaildateBooleanResult(invitionUser == null, RetResultCode.E20010);
			
			user.setInviterId(invitionUser.getUserId());
			// 生成自己的邀请码
			String invitionCodeSelf = RandomUtils.genRandomUpperAlphaAndDec(8);
			UserInfo hasExist = userMapper.fetchUserByInvitionCode(invitionCodeSelf);
			while (hasExist != null) { // 保证邀请码唯一
				invitionCodeSelf = RandomUtils.genRandomUpperAlphaAndDec(8);
			}
			user.setInvitionCode(invitionCodeSelf);
		}
		
		// 创建资金账户
		UserAccount account = new UserAccount();
		account.setAccountId(SequenceUtils.generateDefaultSerialNum());
		account.setUserId(user.getUserId());
		account.setBalance(BigDecimalUtils.genInitValue());
		account.setFreeze(BigDecimalUtils.genInitValue());
		account.setStatus(DDIC.UserAccountStatus.ENABLED.id);
		account.setCreateTime(new Date());
		account.setModifiedTime(new Date());
		
		String code = RandomUtils.generateString(15);
		ActivationCode ac = new ActivationCode();
		ac.setUserId(user.getUserId());
		ac.setCreateDate(new Date());
		ac.setCode(code);
		ac.setStatus(DDIC.Boolean.BOOL_FALSE_0.id);
		
		boolean bool1 = userMapper.insertSelective(user) > 0;
		boolean bool2 = userAccountMapper.insertSelective(account) > 0;
		boolean bool3 = activationCodeMapper.insertSelective(ac) > 0;
		
		boolean result = bool1 && bool2 && bool3;
		if (result) {
			
			// 发送验证邮件
			EmailConfig config = new EmailConfig();
			config.setServerIp(configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_EMAIL_SERVER_IP));
			config.setServerPort(Integer.parseInt(configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_EMAIL_SERVER_PORT)));
			config.setServerUser(configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_EMAIL_SERVER_USER));
			config.setServerPass(configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_EMAIL_SERVER_PASS));
			
			MimeMultipart multipart = new MimeMultipart("related");
			
	        // first part  (the html)
	        BodyPart messageBodyPart = new MimeBodyPart();
	        
	        //用户邮箱注册时发送邮箱验证链接
        	String RegToEmailUrl = configFeign.fetchSystemConfigValue(SysParaKey.SYS_CONFIG_REGS_TO_EMAIL_URL) + "?code=" + code;
        	String htmlText = "<h1>来自HHT.ONE的注册激活邮件，激活请点击以下链接：</h1> <h3>  <a href='"+ RegToEmailUrl +"'> "+ RegToEmailUrl +" </a></h3>";
	        messageBodyPart.setContent(htmlText, "text/html; charset=GBK");
	        // add it
	        multipart.addBodyPart(messageBodyPart);

			EmailUtils.sendHyperText(config, email, "用户注册激活", multipart);
			
			return user;
		}
		
		return null;
	}
	
	@Override
	public boolean activateAccount(String code) throws Exception {

		// 获取验证信息
		ActivationCode ac = activationCodeMapper.fetchInfoByCode(code);
		VaildateHelper.vaildateBooleanResult(ac == null, RetResultCode.E20025);
		
		VaildateHelper.vaildateBooleanResult(DDIC.Boolean.BOOL_TRUE_1.id == ac.getStatus(), RetResultCode.E11001, "激活码已使用");

		UserInfo user = new UserInfo();
		user.setUserId(ac.getUserId());
		user.setStatus(DDIC.UserAccountStatus.ENABLED.id);
		user.setModifiedTime(new Date());
		
		ActivationCode updateAc = new ActivationCode();
		updateAc.setUserId(ac.getUserId());
		updateAc.setStatus(DDIC.Boolean.BOOL_TRUE_1.id);
		
		boolean bool1 = userMapper.updateByPrimaryKeySelective(user) > 0;
		boolean bool2 = activationCodeMapper.updateByPrimaryKeySelective(updateAc) > 0;

		if (bool1 && bool2) {
			// 同步账号
			this.syncAccount(user.getUserId());
			return true;
		}
		
		return false;
	}
	
	public void syncAccount(long userId) throws Exception {
		List<CoinInfo> coinList = this.coinFeign.fetchCacheCoinAllList();
		if (JSUtils.ifCollectionNotEmpty(coinList)) {
			Iterator<CoinInfo> var4 = coinList.iterator();
			while(var4.hasNext()) {
				CoinInfo coin = var4.next();
				this.createCoinWallet(userId, coin.getCoinId());
			}
		}
	}
	
	public void createCoinWallet (long userId, long coinId) throws Exception {
		CoinWallet account = this.coinWalletFeign.fetchCoinWalletInfo(userId, coinId);
		if (account == null) {
			CoinWallet wallet = new CoinWallet();
			wallet.setUserId(userId);
			wallet.setCoinId(coinId);
			wallet.setBalance(BigDecimalUtils.genInitValue());
			wallet.setFreeze(BigDecimalUtils.genInitValue());
			wallet.setWithdraw(BigDecimalUtils.genInitValue());
			wallet.setRecharge(BigDecimalUtils.genInitValue());
			wallet.setStatus(DDIC.CoinWalletStatus.NORMAL.id);
			wallet.setAddress(RandomUtils.genRandomUpperAlphaAndDec(22));
			wallet.setCreateTime(new Date());
			wallet.setModifiedTime(new Date());
			
			this.coinWalletFeign.insertUserCoinWallet(wallet);
		}

	}

	@Override
	public PageInfo<UserInfo> fetchUserPageList(Long userId, String phoneNum, String keyword, Integer status, int showCount, int currentPage) throws Exception {

		PageHelper.startPage(currentPage, showCount);
		Page<UserInfo> page = userMapper.fetchUserPageList(userId, phoneNum, keyword, status);
		
		return new PageInfo<>(page);
	}

	@Override
	public UserInfo fetchUserInfo(Long userId) throws Exception {

		return userMapper.fetchUserByUserId(userId);
	}

	@Override
	public boolean modifyUserInfo(UserInfo user) throws Exception {

		return userMapper.updateByPrimaryKeySelective(user) > 0;
	}

	@Override
	public boolean checkMobileIsExist(String mobile) throws Exception {

		return userMapper.fetchCountByMobile(mobile) > 0;
	}
	
	@Override
	public boolean checkEmailIsExist(String email) throws Exception {
		
		return userMapper.fetchCountByEmail(email) > 0;
	}

	@Override
	public UserInfo login(String mobile, String password) throws Exception {
		
		return userMapper.login(mobile, password);
	}

	@Override
	public boolean modifyPassByMobile(String mobile, String password) throws Exception {

		// 先通过手机号获取用户信息
		UserInfo user = userMapper.fetchUserByMobile(mobile);
		VaildateHelper.vaildateBooleanResult(user == null, RetResultCode.E20019);
		
		UserInfo updateUser = new UserInfo();
		updateUser.setUserId(user.getUserId());
		updateUser.setPassword(password);
		
		return userMapper.updateByPrimaryKeySelective(updateUser) > 0;
	}

	@Override
	public boolean modifyPassword(Long userId, String password, String oldPassword) throws Exception {

		// 判断原密码是否正确
		int count = userMapper.checkOldPasswordIsExist(userId, oldPassword);
		VaildateHelper.vaildateBooleanResult(count <= 0, RetResultCode.E20003);
		
		UserInfo updateUser = new UserInfo();
		updateUser.setUserId(userId);
		updateUser.setPassword(password);
		
		return userMapper.updateByPrimaryKeySelective(updateUser) > 0;
	}

	@Override
	public boolean modifyPayPassword(Long userId, Integer isSetPayPassword, String password, String oldPassword) throws Exception {

		UserInfo user = userMapper.fetchUserByUserId(userId);
		VaildateHelper.vaildateBooleanResult(user == null, RetResultCode.E20019);
		
		// 判断原密码是否正确
		if (DDIC.Boolean.BOOL_TRUE_1.id == isSetPayPassword) {
			int count = userMapper.checkPayPassword(userId, oldPassword);
			VaildateHelper.vaildateBooleanResult(count <= 0, RetResultCode.E20017);
		}
		
		UserInfo updateUser = new UserInfo();
		updateUser.setUserId(userId);
		updateUser.setIsSetPayPassword(DDIC.Boolean.BOOL_TRUE_1.id);
		updateUser.setPayPassword(password);
		
		return userMapper.updateByPrimaryKeySelective(updateUser) > 0;
	}
	
	@Override
	public boolean modifyPayPassByMobile(String mobile, String password) throws Exception {

		// 先通过手机号获取用户信息
		UserInfo user = userMapper.fetchUserByMobile(mobile);
		VaildateHelper.vaildateBooleanResult(user == null, RetResultCode.E20019);
		
		UserInfo updateUser = new UserInfo();
		updateUser.setUserId(user.getUserId());
		updateUser.setPayPassword(password);
		updateUser.setIsSetPayPassword(DDIC.Boolean.BOOL_TRUE_1.id);
		
		return userMapper.updateByPrimaryKeySelective(updateUser) > 0;
	}
	
	@Override
	public boolean addUserBankCard(UserBank userBank) throws Exception {

		return userBankMaper.insertSelective(userBank) > 0;
	}

	@Override
	public boolean checkUserIsRealNameAuth(Long userId) throws Exception {

		UserInfo user = userMapper.queryByPrimaryKey(userId);
		VaildateHelper.vaildateEntityIsNull(user);
		
		if (StringUtils.isNotBlank(user.getRealName()) && StringUtils.isNotBlank(user.getIdCard())) {
			return true;
		}
		
		return false;
	}

	@Override
	public boolean userIdentifyAuth(UserInfo user) throws Exception {

		boolean isAuth = this.checkUserIsRealNameAuth(user.getUserId());
		VaildateHelper.vaildateBooleanResult(isAuth, RetResultCode.E20015);
		
		boolean isExist = userMapper.fetchCountByIdCardNo(user.getIdCard()) > 0;
		VaildateHelper.vaildateBooleanResult(isExist, RetResultCode.E20016);
		
		boolean auth = AliyunUtils.validateIdCard(user.getRealName(), user.getIdCard());
		VaildateHelper.vaildateBooleanResult(!auth, RetResultCode.E11001, "身份认证错误：证件号与姓名不相符");
		
		return userMapper.updateByPrimaryKeySelective(user) > 0;
	}

	@Override
	public List<UserBank> fetchBankListByUserId(Long userId) throws Exception {
		
		return userBankMaper.fetchBankListByUserId(userId);
	}

	@Override
	public boolean checkUserPayPassword(Long userId, String payPassword) throws Exception {

		return userMapper.checkPayPassword(userId, payPassword) > 0;
	}

}
